package com.honghea.rxhttp;

import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.functions.BiFunction;
import io.reactivex.rxjava3.functions.Function;


public class RetryWhenNetworkException implements Function<Observable<? extends Throwable>, Observable<?>> {

    private int count;
    private long delay;
    private long delayIncrease;

    public RetryWhenNetworkException(int count, long delay, long delayIncrease) {
        this.count = count;
        this.delay = delay;
        this.delayIncrease = delayIncrease;
    }

    public RetryWhenNetworkException() {
        this(3,1000,3000);
    }

    public RetryWhenNetworkException(int count, long delay) {
        this(count, delay, 3000);
    }

    @Override
    public Observable<?> apply(Observable<? extends Throwable> observable) throws Exception {
        return observable
                .zipWith(Observable.range(1, count + 1), (BiFunction<Throwable, Integer, Wrapper>) Wrapper::new)
                .flatMap(wrapper->{
                    if ((wrapper.throwable instanceof ConnectException
                            || wrapper.throwable instanceof SocketTimeoutException
                            || wrapper.throwable instanceof TimeoutException)
                            && wrapper.index < count + 1) {
                        return Observable.timer(delay + (wrapper.index - 1) * delayIncrease, TimeUnit.MILLISECONDS);
                    }
                    return Observable.error(wrapper.throwable);
                });
    }


    private class Wrapper {
        private int index;
        private Throwable throwable;

        private Wrapper(Throwable throwable, int index) {
            this.index = index;
            this.throwable = throwable;
        }
    }
}
